﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using CamShared;
using System.Diagnostics;
using System.Threading;
using DavuxLib;

namespace CamServer
{
    public partial class Viewer : DavuxLib.Controls.AeroForm
    {
        DavuxLib.Animation a = new DavuxLib.Animation();
        DavuxLib.AniVariable slideVar = new DavuxLib.AniVariable();
        DavuxLib.AniVariable fadeVar = new DavuxLib.AniVariable();
        int picBeforeHeight = 0;

        int lagMon = 0;
        bool lagShown = false;

        bool UserRequestedClose = true;

        public CamShared.ICamera Camera = null;

        static List<Viewer> Viewers = new List<Viewer>();

        public static void CloseAll()
        {
            foreach (Viewer v in Viewers.ToArray())
            {
                v.CloseAndSave();
            }
        }

        public static void ShowCamera(ICamera cam)
        {
            foreach (Viewer v in Viewers.ToArray())
            {
                if (v.Camera.UID == cam.UID)
                {
                    v.Invoke((MethodInvoker)delegate()
                    {
                        v.Show();
                    });
                    return;
                }
            }
            MakeNewCamera(cam);
        }

        private static void MakeNewCamera(ICamera cam)
        {
            Thread t = new Thread(new ParameterizedThreadStart(NewCamera));
            t.Start(cam);
        }

        private static void NewCamera(object cam)
        {
            Application.Run(new Viewer((ICamera)cam));
        }

        public Viewer(CamShared.ICamera Camera)
        {
            InitializeComponent();
            this.Camera = Camera;
            Viewers.Add(this);
            tmrUI.Interval = 100;
            tmrUI.Enabled = true;

            INetworkCSCamera ncam = Camera as INetworkCSCamera;

            if (ncam != null)
            {
                ncam.Delay = Settings.Get(Camera.Name + "|Delay", ncam.Delay);
                ncam.Quality = Settings.Get(Camera.Name + "|Quality", ncam.Quality);
            }

            mnuRecording.Checked = Settings.Get(Camera.Name + "|Recording", false);
            mnuSharing.Checked = Settings.Get(Camera.Name + "|Unity Sharing", false);

            this.WindowState = FormWindowState.Normal;
            this.StartPosition = FormStartPosition.WindowsDefaultBounds;

            Rectangle Saved = Settings.Get("#" + Camera.Name + "|Size", Rectangle.Empty);


            if (Saved != Rectangle.Empty && IsVisibleOnAnyScreen(Saved))
            {
                this.StartPosition = FormStartPosition.Manual;
                this.DesktopBounds = Saved;

                switch (Settings.Get("#" + Camera.Name + "|WindowMax", 1))
                {
                    case 1:
                        this.WindowState = FormWindowState.Normal;
                        break;
                    case 2:
                        this.WindowState = FormWindowState.Maximized;
                        break;
                    case 3:
                        this.WindowState = FormWindowState.Minimized;
                        break;
                }
            }
            else
            {
                this.StartPosition = FormStartPosition.CenterScreen;

                // we can still apply the saved size
                //this.Size = Settings.Default.WindowPosition.Size;
            }

            _GlassArea.Bottom = ClientRectangle.Height - pic.Height;

        }

        private void Viewer_Load(object sender, EventArgs e)
        {
            lblCam.Text = this.Text = Settings.Get(Camera.Name + "|FriendlyName", Camera.Name);
            try
            {
                Camera.OnFrame += new CamShared.CamShared.FrameReceived(Camera_OnFrame);
                Camera.OnError += new CamShared.CamShared.CameraError(Camera_OnError);

                Camera.Activate();
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Error Activating Camera: " + ex);
            }


        }

        void Camera_OnError(ICamera cam, string Error, bool Fatal)
        {
            if (this.IsHandleCreated)
            {
                this.Invoke((MethodInvoker)delegate()
                {
                    MessageBox.Show("Error: " + Error, "Camera Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    if (Fatal)
                    {
                        Camera.Deactivate();
                    }
                });
            }
        }

        void Camera_OnFrame(ICamera cam, Image frame)
        {
            lagMon = 0;
            if (this.IsHandleCreated)
            {
                this.Invoke((MethodInvoker)delegate()
                {
                    pic.Image = (Image)frame.Clone();
                    if (aFewTimes < 10)
                    {
                        aFewTimes++;
                        Settings.Get(cam.Name + "|Height", frame.Height);
                        Settings.Get(cam.Name + "|Width", frame.Width);
                        Settings.Get(cam.Name + "|Recording Height", frame.Height);
                        Settings.Get(cam.Name + "|Recording Width", frame.Width);
                    }
                });
            }
        }

        int aFewTimes = 0;

        private void tmrUI_Tick(object sender, EventArgs e)
        {
            lagMon++;
            if (lagMon >= 50)
            {
                // cam not working

                if (!lagShown)
                {
                    lagShown = true;
                    slideVar.StartValue = pInactive.Height * -1;
                    slideVar.Endvalue = pInactive.Top;
                    picBeforeHeight = pic.Height;
                    fadeVar.StartValue = 0;
                    fadeVar.Endvalue = 255;

                    if (a.Animating)
                    {
                        a.StopAnimation();
                    }
                    a.OnTick += new DavuxLib.Animation.AnimationTick(a_OnTick);
                    a.OnEndAnimation += new DavuxLib.Animation.AnimationTick(a_OnEndAnimation);
                    a.StartAnimation(250);
                }
            }
            else
            {
                // cam OK

                if (lagShown)
                {
                    // hide it!
                    lagShown = false;

                    slideVar.StartValue = pInactive.Top;
                    slideVar.Endvalue = pInactive.Height * -1;
                    picBeforeHeight = pic.Height;
                    fadeVar.StartValue = 255;
                    fadeVar.Endvalue = 0;

                    if (a.Animating)
                    {
                        a.StopAnimation();
                    }
                    a.OnTick += new DavuxLib.Animation.AnimationTick(a2_OnTick);
                    a.OnEndAnimation += new DavuxLib.Animation.AnimationTick(a2_OnEndAnimation);
                    a.StartAnimation(250);
                }
            }
        }

        private void Viewer_FormClosed(object sender, FormClosedEventArgs e)
        {
            Application.DoEvents();
            Camera.Deactivate();
        }

        public void CloseAndSave()
        {
            if (this.IsHandleCreated)
            {
                if (this.InvokeRequired)
                {
                    this.Invoke((MethodInvoker)delegate()
                    {
                        UserRequestedClose = false;
                        Close();
                    });
                }
                else
                {
                    UserRequestedClose = false;
                    Close();
                }
            }
        }


        private bool IsVisibleOnAnyScreen(Rectangle rect)
        {
            foreach (System.Windows.Forms.Screen screen in System.Windows.Forms.Screen.AllScreens)
            {
                if (screen.WorkingArea.IntersectsWith(rect))
                {
                    return true;
                }
            }
            return false;
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);

            Settings.Set("#" + Camera.Name + "|WasOpen", !UserRequestedClose);

            Viewers.Remove(this);

            // only save the WindowState if Normal or Maximized
            switch (this.WindowState)
            {
                case FormWindowState.Normal:
                    Settings.Set("#" + Camera.Name + "|WindowMax", 1);
                    break;
                case FormWindowState.Maximized:
                    Settings.Set("#" + Camera.Name + "|WindowMax", 2);
                    break;
                default:
                    Settings.Set("#" + Camera.Name + "|WindowMax", 3);
                    break;
            }

            // reset window state to normal to get the correct bounds
            // also make the form invisible to prevent distracting the user
            this.Visible = false;
            this.WindowState = FormWindowState.Normal;


            Settings.Set("#" + Camera.Name + "|Size", this.DesktopBounds);
        }





        void a_OnEndAnimation(DavuxLib.Animation animator)
        {
            a.OnTick -= new DavuxLib.Animation.AnimationTick(a_OnTick);
            a.OnEndAnimation -= new DavuxLib.Animation.AnimationTick(a_OnEndAnimation);
        }


        void a_OnTick(DavuxLib.Animation animator)
        {
            if (this.IsHandleCreated)
            {
                try
                {
                    this.Invoke((MethodInvoker)delegate()
                    {
                        pInactive.Top = (int)animator.GetVariable(slideVar);
                        pInactive.Visible = true;
                        pic.Top = pInactive.Top + pInactive.Height;

                        //Height = beforeHeight + pic.Top;
                        pic.Height = picBeforeHeight - pic.Top;
                    });
                }
                catch (Exception ex)
                {

                }
            }
        }



        void a2_OnEndAnimation(DavuxLib.Animation animator)
        {
            a.OnTick -= new DavuxLib.Animation.AnimationTick(a2_OnTick);
            a.OnEndAnimation -= new DavuxLib.Animation.AnimationTick(a2_OnEndAnimation);
            if (this.IsHandleCreated)
            {
                try
                {
                    this.Invoke((MethodInvoker)delegate()
                    {

                        pInactive.Top = 0;
                        pInactive.Visible = false;
                        pic.Top = 0;
                    });
                }
                catch (Exception ex)
                {

                }
            }
        }


        void a2_OnTick(DavuxLib.Animation animator)
        {
            if (this.IsHandleCreated)
            {
                try
                {
                    this.Invoke((MethodInvoker)delegate()
                    {
                        pInactive.Top = (int)animator.GetVariable(slideVar);

                        pic.Top = pInactive.Top + pInactive.Height;

                        //Height = beforeHeight + pic.Top;
                        pic.Height = picBeforeHeight - pInactive.Top;
                    });
                }
                catch (Exception ex)
                {

                }
            }
        }

        private void btnReset_Click(object sender, EventArgs e)
        {

        }

        private void btnOptions_Click(object sender, EventArgs e)
        {
            if (Settings.Get(Camera.Name + "|ProtocolVersion", "") != "")
            {
                mnuSpeed.Visible = true;
            }
            options_menu.Show(btnOptions, new Point());
        }

        private void mnuRecording_Click(object sender, EventArgs e)
        {
            mnuRecording.Checked = !mnuRecording.Checked;
            Settings.Set(Camera.Name + "|Recording", mnuRecording.Checked);
        }

        private void mnuSharing_Click(object sender, EventArgs e)
        {
            mnuSharing.Checked = !mnuSharing.Checked;
            Settings.Set(Camera.Name + "|Unity Sharing", mnuSharing.Checked);
        }

        private void mnuProperties_Click(object sender, EventArgs e)
        {
            CamServer.CameraProperties c = new CamServer.CameraProperties(Camera);
            c.StartPosition = FormStartPosition.CenterParent;
            c.ShowDialog(this);
        }

        private void menuItem1_Click(object sender, EventArgs e)
        {
            if (Settings.Get(Camera.Name + "|ProtocolVersion", "") != "1.0")
            {
                ChangeSpeed cs = new ChangeSpeed(Camera);
                cs.StartPosition = FormStartPosition.CenterParent;
                if (cs.ShowDialog(this) == DialogResult.OK)
                {
                    INetworkCSCamera ncam = Camera as INetworkCSCamera;
                    if (ncam != null)
                    {
                        Settings.Set(Camera.Name + "|Delay", ncam.Delay);
                        Settings.Set(Camera.Name + "|Quality", ncam.Quality);
                    }
                }
            }
            else
            {
                MessageBox.Show("This feature is not supported by the remote Camera.  Please Update CamServer on the remote host.", "CamServer Protocol Mismatch", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

    }
}
